/* 
 * File:   Utiles.cpp
 * Author: Gabriel Fainstein
 * 
 * Created on 19 de mayo de 2013, 19:30
 */

#include "common_FileUtils.h"
#include <string.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include "common_md5.h"

using namespace std;
using namespace TP::Archivos;

const unsigned int FileUtils::bytesPorChunk = 1048576;   // 1 MB

FileUtils::FileUtils() {}

bool FileUtils::ObtenerNombreArchivos(const std::string& path, 
                                   LNombreArchivo& l) const 
{
    DIR * dir = opendir(path.c_str());
    if(dir == NULL)
        return false;
    else
    {
        struct dirent * ent = readdir(dir);
        while(ent != NULL)
        {
            std::string nom = ent->d_name;
            if(nom != "." && nom != "..")
                l.push_back(nom);
            ent = readdir(dir);
        }
        closedir(dir);
        return true;
    } 
    
}

bool FileUtils::ObtenerFullPathArchivo(const std::string& path, 
                                    LPathArchivo& l) const
{
    DIR * dir = opendir(path.c_str());
    if(dir == NULL) return false;
    else
    {
        struct dirent * ent = readdir(dir);
        while(ent != NULL)
        {
            std::string nom = ent->d_name;
            if(nom != "." && nom != "..")
            {
                nom.insert(0, path);
                l.push_back(nom);
            }
            ent = readdir(dir);
        }
        closedir(dir);
        return true;
    }     
}


bool FileUtils::DirectorioExistente(const std::string& path)
{
    bool estado = true;
    DIR* dir = opendir(path.c_str());
    if(dir == NULL) estado = false;
    else closedir(dir);
    return estado;
}

void FileUtils::ComputarChunk(uint8_t* &pData, size_t &pDataLongitud, const std::string& pRutaCompletaArchivo, unsigned int pNumeroChunk) {

    pData = NULL;
    pDataLongitud = 0;
    
    std::ifstream file(pRutaCompletaArchivo.c_str(), std::ios_base::in | std::ios_base::binary);
    
    if(! file.is_open()) return;

    // Verifico que sea un nro de chunk valido
    file.seekg(0, std::ios_base::end);
    if ((pNumeroChunk * FileUtils::bytesPorChunk) >= file.tellg()) return;
    
    pData = new uint8_t [FileUtils::bytesPorChunk];
    bzero (pData, FileUtils::bytesPorChunk);
    
    file.seekg(pNumeroChunk * FileUtils::bytesPorChunk, std::ios_base::beg);
    file.read((char*) pData, FileUtils::bytesPorChunk);
    
    pDataLongitud = file.gcount();
}

size_t FileUtils::CalcularCantidadChunks(const string &pRutaCompletaArchivo){

    size_t tamanioArchivo = 0;
    std::ifstream file(pRutaCompletaArchivo.c_str(), std::ios::binary|std::ios::ate);
    
    if (file.is_open())
    {
        tamanioArchivo = file.tellg();
        tamanioArchivo = (size_t) ceil(tamanioArchivo / FileUtils::bytesPorChunk);
        file.close();
    }
    
    return tamanioArchivo;
}

string FileUtils::GetHash (const string& pRutaCompletaArchivo, const size_t pIndiceChunk){
    
    string hash = "";
    uint8_t* buffer = NULL;
    size_t bufferLongitud = 0;
    
    ComputarChunk(buffer, bufferLongitud, pRutaCompletaArchivo, pIndiceChunk);
    
    if (bufferLongitud > 0)
    {
        char* hashStr = new char[34];
        bzero (hashStr, 34);
        calcularHashMD5Bloque((char*) buffer, bufferLongitud, hashStr);
        hash = hashStr;
        
        delete [] hashStr;
        delete [] buffer;
    }
    
    return hash;
}